package com.an.blog.utils;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.an.blog.admin.domain.BlogArticle;
import com.an.blog.admin.domain.BlogArticleTag;
import com.an.blog.admin.domain.BlogTag;
import com.an.blog.mapper.BlogArticleTagMapper;
import com.an.blog.service.IBlogCategoryService;
import com.an.blog.service.IBlogTagService;
import com.an.blog.third.es.domain.EsBlogArticle;
import com.an.blog.web.domain.vo.BlogArticleTagNameVo;
import com.an.blog.web.domain.vo.BlogArticleWebVo;
import com.an.common.constant.BlogConstants;
import com.an.common.constant.CacheConstants;
import com.an.common.core.domain.BaseEntity;
import com.an.common.core.domain.entity.SysDictData;
import com.an.common.core.domain.entity.SysUser;
import com.an.common.enums.ArticleEsOperationType;
import com.an.common.helper.LoginHelper;
import com.an.common.utils.StreamUtils;
import com.an.common.utils.redis.RedisUtils;
import com.an.common.utils.spring.SpringUtils;
import com.an.producer.MqProducer;
import com.an.system.domain.vo.SysOssVo;
import com.an.system.mapper.SysUserMapper;
import com.an.system.service.ISysConfigService;
import com.an.system.service.ISysDictDataService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;

import java.util.*;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;

/**
 * 博客通用实用程序
 *
 * @author Ann
 * @date 2024/06/13
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class BlogUniversalUtil {

    private static final IBlogCategoryService CATEGORY_SERVICE = SpringUtils.getBean(IBlogCategoryService.class);
    private static final SysUserMapper USER_MAPPER = SpringUtils.getBean(SysUserMapper.class);
    private static final ISysDictDataService DICT_DATA_SERVICE = SpringUtils.getBean(ISysDictDataService.class);
    private static final ISysConfigService SYS_CONFIG_SERVICE = SpringUtils.getBean(ISysConfigService.class);
    private static final IBlogTagService BLOG_TAG_SERVICE = SpringUtils.getBean(IBlogTagService.class);
    private static final BlogArticleTagMapper ARTICLE_TAG_MAPPER = SpringUtils.getBean(BlogArticleTagMapper.class);
    private static final MqProducer MQ_PRODUCER = SpringUtils.getBean(MqProducer.class);


    /**
     * 查询用户头像
     *
     * @param blogArticleList 博客文章列表
     * @return {@link Map }<{@link String }, {@link String }>
     * @author: Ann
     * @createDate: 2023/05/27 08:05:48
     * @version: 1.0.0
     */
    private static List<SysUser> queryUserInfo(List<BlogArticle> blogArticleList) {
        Set<String> userNamesSet = StreamUtils.toSet(blogArticleList, BaseEntity::getCreateBy);
        return USER_MAPPER.selectList(new LambdaQueryWrapper<SysUser>().select(SysUser::getUserName,
            SysUser::getNickName, SysUser::getUserId,
            SysUser::getAvatar).in(SysUser::getUserName, userNamesSet));
    }

    /**
     * 构建web查询包装标签
     *
     * @param articles 文章
     * @return {@link Map }<{@link Long }, {@link String[] }>
     * @author: Ann
     * @createDate: 2023/06/07 18:44:45
     * @version: 1.0.0
     */
    private static Map<Long, String[]> queryTagList(List<BlogArticle> articles) {
        if (CollUtil.isNotEmpty(articles)) {
            List<Long> articleIds = StreamUtils.toList(articles, BlogArticle::getArticleId);
            QueryWrapper<BlogArticleTag> wrapper = Wrappers.query();
            wrapper.in("bat.article_id", articleIds);
            List<BlogArticleTagNameVo> blogArticleTagNameVos = ARTICLE_TAG_MAPPER.selectTagList(wrapper);
            // 使用Stream API转换为Map<Long, String[]>类型
            return blogArticleTagNameVos.stream()
                .collect(Collectors.groupingBy(BlogArticleTagNameVo::getArticleId,
                    Collectors.mapping(BlogArticleTagNameVo::getTagName, Collectors.toList())))
                .entrySet().stream()
                .collect(Collectors.toMap(Map.Entry::getKey,
                    entry -> entry.getValue().toArray(new String[0])));
        }
        return Collections.emptyMap();
    }

    /**
     * 是否点赞了，点赞了设置为true,否则false
     *
     * @param domain     域
     * @param key        钥匙
     * @param setIsLiked SET被点赞
     * @author Ann
     * @date 2024/06/13
     */
    public static <T> void isLiked(T domain, String key, BiConsumer<T, Boolean> setIsLiked) {
        //1.获取登录用户
        Long userId = LoginHelper.getUserId();
        //2.判断用户是否点过赞
        boolean isMember = RedisUtils.isScoreSortedSetMember(key, userId);
        setIsLiked.accept(domain, isMember);
    }


    /**
     * 设置文章门户展示参数
     *
     * @param returnArticle       返回文章
     * @param categoryId          类别 ID
     * @param articleType         文章类型
     * @param articleId           文章编号
     * @param createBy            创建者
     * @param setCategoryName     设置类别名称
     * @param setArticleTypeLabel 设置商品类型标签
     * @param setAvatar           设置头像
     * @param setCreateBy         设置创建者
     * @param setAuthorId         设置作者 ID
     * @param setTags             设置标签
     * @author Ann
     * @date 2024/06/13
     */
    public static <T> void setArticleWebParameters(T returnArticle, Long categoryId, String articleType, Long articleId,
                                                   String createBy, BiConsumer<T, String> setCategoryName,
                                                   BiConsumer<T, String> setArticleTypeLabel, BiConsumer<T, String> setAvatar,
                                                   BiConsumer<T, String> setCreateBy, BiConsumer<T, Long> setAuthorId,
                                                   BiConsumer<T, String[]> setTags) {
        String categoryName = CATEGORY_SERVICE.queryById(categoryId).getCategoryName();
        //文章类型
        String articleTypeLabel = DICT_DATA_SERVICE.selectDictLabel("blog_article_type", articleType);
        //tagNames
        List<BlogTag> blogTags = BLOG_TAG_SERVICE.queryTagNamesByArticleId(articleId);
        //查询用户头像和昵称
        SysUser sysUser = USER_MAPPER.selectOne(new LambdaQueryWrapper<SysUser>().select(SysUser::getUserId,
                SysUser::getUserName, SysUser::getNickName, SysUser::getAvatar)
            .eq(SysUser::getUserName, createBy));
        String[] tagNames = blogTags.stream()
            .map(BlogTag::getTagName)
            .toArray(String[]::new);
        setCategoryName.accept(returnArticle, categoryName);
        setArticleTypeLabel.accept(returnArticle, articleTypeLabel);
        setAvatar.accept(returnArticle, sysUser.getAvatar());
        setCreateBy.accept(returnArticle, sysUser.getNickName());
        setAuthorId.accept(returnArticle, sysUser.getUserId());
        setTags.accept(returnArticle, tagNames);
    }


    /**
     * 构建文章 Web 列表4 ES
     *
     * @param blogArticleList 博客文章列表
     * @return {@link List }<{@link EsBlogArticle }>
     * @author Ann
     * @date 2024/06/13
     */
    public static List<EsBlogArticle> buildArticleWebList4Es(List<BlogArticle> blogArticleList) {
        // 查询博客文章类型字典数据
        SysDictData sysDictData = new SysDictData();
        sysDictData.setDictType("blog_article_type");
        List<SysDictData> dictData = DICT_DATA_SERVICE.selectDictDataList(sysDictData);
        // 将字典数据转换为字典值和字典标签的映射关系
        Map<String, String> dicDataMap = StreamUtils.toMap(dictData, SysDictData::getDictValue, SysDictData::getDictLabel);

        // 查询文章标签列表
        Map<Long, String[]> articleTagMap = queryTagList(blogArticleList);

        // 查询用户信息
        List<SysUser> users = queryUserInfo(blogArticleList);
        // 将用户列表转换为以用户名为键的用户对象映射关系
        Map<String, SysUser> userNameUserMap = StreamUtils.toIdentityMap(users, SysUser::getUserName);

        // 查询文章图片信息
        Map<Long, SysOssVo> ossIdSysOssMap = ConvertUtil.convert2OssIdSysOssMap(blogArticleList, BlogArticle::getArticleImage);

        // 构建EsBlogArticle列表
        return blogArticleList.stream().map(blogArticle -> {
            // 将BlogArticle转换为EsBlogArticle对象
            EsBlogArticle esBlogArticle = BeanUtil.toBean(blogArticle, EsBlogArticle.class);
            // 设置文章类型
            esBlogArticle.setArticleType(dicDataMap.get(esBlogArticle.getArticleType()));
            // 设置文章标签
            esBlogArticle.setTags(articleTagMap.get(blogArticle.getArticleId()));
            // 设置作者头像
            esBlogArticle.setAvatar(userNameUserMap.get(blogArticle.getCreateBy()).getAvatar());
            // 设置文章图片
            esBlogArticle.setArticleImage(ossIdSysOssMap.get(blogArticle.getArticleImage()).getUrl());
            // 设置作者ID
            esBlogArticle.setAuthorId(userNameUserMap.get(blogArticle.getCreateBy()).getUserId());
            // 设置创建者昵称
            esBlogArticle.setCreateBy(userNameUserMap.get(blogArticle.getCreateBy()).getNickName());
            return esBlogArticle;
        }).collect(Collectors.toList());
    }

    /**
     * 构建文章 Web 列表
     *
     * @param blogArticleList 博客文章列表
     * @return {@link List }<{@link BlogArticleWebVo }>
     * @author Ann
     * @date 2024/06/13
     */
    public static List<BlogArticleWebVo> buildArticleWebList(List<BlogArticle> blogArticleList) {
        // 查询文章标签列表
        Map<Long, String[]> articleTagMap = queryTagList(blogArticleList);
        // 查询用户信息
        List<SysUser> users = queryUserInfo(blogArticleList);
        // 将用户列表转换为以用户名为键的用户对象映射关系
        Map<String, SysUser> userNameUserMap = StreamUtils.toIdentityMap(users, SysUser::getUserName);
        // 查询文章图片信息
        Map<Long, SysOssVo> ossIdSysOssMap = ConvertUtil.convert2OssIdSysOssMap(blogArticleList, BlogArticle::getArticleImage);
        // 构建并返回BlogArticleWebVo列表
        return blogArticleList.stream().map(blogArticle -> {
            // 设置是否点赞的状态
            isLiked(blogArticle, CacheConstants.ARTICLE_LIKED_KEY + blogArticle.getArticleId(), BlogArticle::setIsLiked);
            // 将BlogArticle转换为BlogArticleWebVo对象
            BlogArticleWebVo blogArticleWebVo = BeanUtil.toBean(blogArticle, BlogArticleWebVo.class);
            // 设置文章标签
            blogArticleWebVo.setTags(articleTagMap.get(blogArticle.getArticleId()));
            // 设置作者头像
            blogArticleWebVo.setAvatar(userNameUserMap.get(blogArticle.getCreateBy()).getAvatar());
            // 设置文章图片URL
            blogArticleWebVo.setArticleImage(ossIdSysOssMap.get(blogArticle.getArticleImage()).getUrl());
            // 设置创建者昵称
            blogArticleWebVo.setCreateBy(userNameUserMap.get(blogArticle.getCreateBy()).getNickName());
            return blogArticleWebVo;
        }).collect(Collectors.toList());
    }


    /**
     * Handle es Operate
     *
     * @param blogArticle 博客文章
     * @param articleIds  文章 IDS
     * @param method      方法
     * @author Ann
     * @date 2024/06/29
     */
    public static void handleEsOperate(BlogArticle blogArticle, Collection<Long> articleIds, String method) {
        //如果开启了ES,进行对应的Es操作
        if (!SYS_CONFIG_SERVICE.selectEsEnabled()) {
            return;
        }
        ArticleEsOperationType operationType = ArticleEsOperationType.findOperationType(method);
        assert operationType != null;
        String exchange = operationType.getExchange();
        String key = operationType.getKey();
        //如果是删除操作，传ids参数
        if (BlogConstants.ARTICLE_DELETE.equals(operationType.getMethod())) {
            //删除需要传递Ids
            MQ_PRODUCER.sendMessage(exchange, key, articleIds);
            return;
        }
        MQ_PRODUCER.sendMessage(exchange, key, blogArticle);
    }
}
